package com.seednia.module.util.messagesender.impl;

import java.io.File;
import java.io.StringWriter;
import java.util.HashMap;
import java.util.Map;
import java.util.Properties;

import javax.activation.DataHandler;
import javax.activation.DataSource;
import javax.activation.FileDataSource;
import javax.mail.Authenticator;
import javax.mail.BodyPart;
import javax.mail.Message;
import javax.mail.Multipart;
import javax.mail.PasswordAuthentication;
import javax.mail.Session;
import javax.mail.Transport;
import javax.mail.internet.InternetAddress;
import javax.mail.internet.MimeBodyPart;
import javax.mail.internet.MimeMessage;
import javax.mail.internet.MimeMultipart;

import org.apache.commons.lang.StringUtils;

import com.seednia.foundation.framework.service.RequestContext;
import com.seednia.foundation.framework.service.ServiceContainer;
import com.seednia.module.core.message.dto.MessageDto;
import com.seednia.module.util.messagesender.IMessageSender;
import com.seednia.module.util.template.service.ITemplate;
import com.seednia.module.util.template.service.ITemplateService;

/**
 * Concrete Provider that sends SMTP emails
 * 
 * @author Young Suk Ahn
 *
 */
public class EmailSenderProvider implements IMessageSender {

	public static final String PNAME_FROM = "from";
	public static final String PNAME_SMTP_HOST = "smtp-host";
	public static final String PNAME_SMTP_PORT = "smtp-port";
	public static final String PNAME_SMTP_USER = "smtp-user";
	public static final String PNAME_SMTP_PASSWORD = "smtp-password";

	private String id; // MessageSender iD
	
	private String from;
	private String smtpHost; 
	private String smtpPort;
	private String smtpUser;
	private String smtpPassword;
	
	@Override
	public String getId() {
		return this.id;
	}
	public void setId(String id) {
		this.id = id;
	}
	
	@Override
	public Integer getType() {
		return MessageDto.DELIVERY_EMAIL;
	}
	
	public void initialize(Properties config) {
		final String PREFIX = "email.";
		this.from = config.getProperty(PREFIX+PNAME_FROM);
		this.smtpHost = config.getProperty(PREFIX+PNAME_SMTP_HOST);
		this.smtpPort = config.getProperty(PREFIX+PNAME_SMTP_PORT);
		this.smtpUser = config.getProperty(PREFIX+PNAME_SMTP_USER);
		this.smtpPassword = config.getProperty(PREFIX+PNAME_SMTP_PASSWORD);
	}

	@Override
	public void sendMessage(RequestContext requestContext, MessageDto messageDto) 
	{

		//if ( messageDto.getRecipientDto() ==  null || StringUtils.isEmpty( messageDto.getRecipientDto().getEmail()) )
		//	throw new IllegalArgumentException("Recipient is null or recipient's email is empty");
		
		// Get session
		Session session = createMailSession();

		// Define message
		MimeMessage message = new MimeMessage(session);
		try {
			message.setFrom(new InternetAddress(from));
			String recipientEmail = (messageDto.getRecipientDto() != null) 
					? messageDto.getRecipientDto().getEmail() : messageDto.getRecipientAddress();
			message.addRecipient(Message.RecipientType.TO, new InternetAddress(recipientEmail));
			message.setSubject(messageDto.getSubject());

			if (messageDto.getMediaUrl() != null) {
				BodyPart messageBodyPart = new MimeBodyPart();
				messageBodyPart.setText(messageDto.getBody());
	
				Multipart multipart = new MimeMultipart();
				multipart.addBodyPart(messageBodyPart);
		
				messageBodyPart = new MimeBodyPart();
				// get file from messageDto.getMediaUrl();
				File file = null;
				DataSource source = new FileDataSource(file);
				messageBodyPart.setDataHandler(new DataHandler(source));
				messageBodyPart.setFileName(messageDto.getMediaTitle());
				multipart.addBodyPart(messageBodyPart);
				message.setContent(multipart);
			} else {
				// Put parts in message
				//message.setText(messageDto.getBody());
				
				if (StringUtils.isNotEmpty(messageDto.getTemplateName()) ) {
					ITemplateService templateService = ServiceContainer.getInstance().getByType(ITemplateService.class);
					
					ITemplate template = templateService.getTemplate(messageDto.getTemplateName());
					Map<String, Object> model = new HashMap<String, Object>();
					model.put("requestContext", requestContext);
					model.put("message", messageDto);
					StringWriter sw = new StringWriter();
					template.process(model, sw);
					message.setContent(sw.toString(), "text/html; charset=utf-8");
				} else {
					message.setContent(messageDto.getBody(), "text/html; charset=utf-8");
				}

			}
				
			// Send the message
			Transport.send(message);
			
			// Send the message using specific transport
			/*
			Transport transport = session.getTransport("smtps");
			transport.connect(this.smtpHost, this.smtpUser, this.smtpPassword);
			transport.sendMessage(message, message.getAllRecipients());
			transport.close();
			*/
		} catch (Exception e) {
			throw new IllegalArgumentException(e);
		}
		
	}


	Session createMailSession()
	{
		Properties mailProps = new Properties();
		mailProps.put("mail.smtp.from", from);
		mailProps.put("mail.smtp.host", smtpHost);
		mailProps.put("mail.smtp.port", smtpPort);
		mailProps.put("mail.smtp.user", smtpUser);  
		mailProps.put("mail.smtp.auth", "true");
		mailProps.put("mail.smtp.starttls.enable", "true");
		mailProps.put("mail.smtp.debug", "true");

		/*
		mailProps.put("mail.smtps.auth", "true");
		mailProps.put("mail.smtps.host", smtpHost);
		mailProps.put("mail.transport.protocol", "smtps");
		*/

		mailProps.put("mail.smtp.socketFactory.port", smtpPort);
		mailProps.put("mail.smtp.socketFactory.class", "javax.net.ssl.SSLSocketFactory");
		mailProps.put("mail.smtp.socketFactory.fallback", "false");

		Session mailSession = Session.getDefaultInstance(mailProps, new SmtpAuthenticator(smtpUser, smtpPassword));
		//Session mailSession = Session.getDefaultInstance(mailProps, null);

		return mailSession;
	}
	
	private class SmtpAuthenticator extends Authenticator
	{
		private String user;
		private String password;
		
		public SmtpAuthenticator(String user, String password)
		{
			this.user = user;
			this.password = password;  
		}
		
		@Override
		protected PasswordAuthentication getPasswordAuthentication() {
			return new PasswordAuthentication(this.user, this.password);
		}
	}
}
